package com.lry.basic.jvm.rpc;

import java.util.ArrayList;
import java.util.List;

/**
 * @author:刘仁有
 * @desc:
 * @email:953506233@qq.com
 * @data:2019/12/23
 */
public class ClassModifier {
    //class 文件中常量池起始偏移
    private static final int CONSTANT_POOL_COUNT_INDEX = 8;
    //CONSTANT_UTF8_INFO常量的tag标志
    private static final int CONSTANT_UTF8_INFO = 1;

    //常量池中常量所占的长度，CONSTANT_UTF8_INFO除外吗，因为他是不定长的
    private static final int[] CONSTANT_ITEM_LENGTH = {-1,-1,-1,5,5,9,9,3,3,5,5,5,5};

    private static final int u1 = 1;
    private static final int u2= 2;

    private byte[] classByte;

    public ClassModifier(byte[] classByte){
        this.classByte = classByte;
        System.out.println(getStringConstant());
    }

    /**
     * 修改常量池中CONSTANT_UTF8_INFO 常量的内容
     * @param oldStr
     * @param newStr
     * @return
     */
    public byte[] modifyUTF8Constant(String oldStr,String newStr){
        int cpc = getConstantPoolCount();//拿到8-9字节代表的十进制数，即有多少项常量
        int offset = CONSTANT_POOL_COUNT_INDEX+u2;//跳到第一项常量
        for(int i=0;i<cpc;i++){
            int tag = ByteUtils.bytes2Int(classByte,offset,u1);//拿到当前常量的tag标志
            //如果tag是CONSTANT_UTF8_INFO
            if(tag==CONSTANT_UTF8_INFO){
                //拿到u8的length，
                int len = ByteUtils.bytes2Int(classByte,offset+u1,u2);
                offset+=(u1+u2);//移到u8的bytes内容
                //从这里拿出len长度的字节转成string
                String str = ByteUtils.bytes2String(classByte,offset,len);
                //如果找到了要替换的旧串
                if(str.equalsIgnoreCase(oldStr)){
                    byte[]strBytes =ByteUtils.string2Bytes(newStr);
                    byte[]strLen = ByteUtils.int2Bytes(newStr.length(),u2);
                    classByte = ByteUtils.bytesReplace(classByte,offset-u2,u2,strLen);
                    classByte = ByteUtils.bytesReplace(classByte,offset,len,strBytes);
                    return classByte;
                }
                //没有的话就加上len，此项常量遍历完成
                else{
                    offset+=len;
                }
            }else{
                //{-1,-1,-1,5,5,9,9,3,3,5,5,5,5}
                offset+=CONSTANT_ITEM_LENGTH[tag];
            }
        }
        return classByte;
    }

    private int getConstantPoolCount() {
        return ByteUtils.bytes2Int(classByte,CONSTANT_POOL_COUNT_INDEX,u2);
    }


    public List<String> getStringConstant(){
        List<String> list = new ArrayList<>();
        int cpc = getConstantPoolCount();//拿到8-9字节代表的十进制数，即有多少项常量
        int offset = CONSTANT_POOL_COUNT_INDEX+u2;//跳到第一项常量
        for(int i=0;i<cpc;i++){
            int tag = ByteUtils.bytes2Int(classByte,offset,u1);//拿到当前常量的tag标志
            //如果tag是CONSTANT_UTF8_INFO
            if(tag==CONSTANT_UTF8_INFO){
                //拿到u8的length，
                int len = ByteUtils.bytes2Int(classByte,offset+u1,u2);
                offset+=(u1+u2);//移到u8的bytes内容
                //从这里拿出len长度的字节转成string
                String str = ByteUtils.bytes2String(classByte,offset,len);
                list.add(str);
                offset+=len;
            } else{
                //{-1,-1,-1,5,5,9,9,3,3,5,5,5,5}
                offset+=CONSTANT_ITEM_LENGTH[tag];
            }
        }
        return list;
    }
}
